﻿// See https://aka.ms/new-console-template for more information
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Tensorflow;
using TensorFlowTest;
using static Tensorflow.Binding;
using static Tensorflow.KerasApi;
using Console = Colorful.Console;


var parsedArgs = ParseArgs(args);

var examples = Assembly.GetEntryAssembly().GetTypes()
    .Where(x => x.GetInterfaces().Contains(typeof(IExample)))
    //.Where(x => x.Name == nameof(MnistGAN))
    //.Where(x => x.Name == nameof(ImageClassificationKeras))
    //.Where(x => x.Name == nameof(WeatherPrediction))
    .ToArray();

Console.WriteLine(Environment.OSVersion, Color.Yellow);
Console.WriteLine($"64Bit Operating System: {Environment.Is64BitOperatingSystem}", Color.Yellow);
Console.WriteLine($".NET CLR: {Environment.Version}", Color.Yellow);
Console.WriteLine($"TensorFlow Binary v{tf.VERSION}", Color.Yellow);
Console.WriteLine($"TensorFlow.NET v{Assembly.GetAssembly(typeof(TF_DataType)).GetName().Version}", Color.Yellow);
Console.WriteLine($"TensorFlow.Keras v{Assembly.GetAssembly(typeof(KerasApi)).GetName().Version}", Color.Yellow);
Console.WriteLine(Environment.CurrentDirectory, Color.Yellow);

int finished = 0;
var errors = new List<string>();
var success = new List<string>();

var sw = new Stopwatch();

for (var i = 0; i < examples.Length; i++)
{
    var (isSuccess, name) = (true, "");
    sw.Restart();
    (isSuccess, name) = RunExamples(examples[i], parsedArgs);
    sw.Stop();

    if (isSuccess)
    {
        success.Add($"Example: {name} in {sw.Elapsed.TotalSeconds}s");
        // only successfully run examples could be sorted as finished
        finished++;
    }
    else
        errors.Add($"Example: {name} in {sw.Elapsed.TotalSeconds}s");


    keras.backend.clear_session();
}

if (parsedArgs.ContainsKey("ex"))
{
    printRunInfo(finished, examples.Length);
    return;
}

success.ForEach(x => Console.WriteLine($"{x} is OK!", Color.White));
errors.ForEach(x => Console.WriteLine($"{x} is Failed!", Color.Red));

printRunInfo(finished, examples.Length);

static void printRunInfo(int finished, int examplesLength)
{
    Console.WriteLine(Environment.OSVersion, Color.Yellow);
    Console.WriteLine($"64Bit Operating System: {Environment.Is64BitOperatingSystem}", Color.Yellow);
    Console.WriteLine($".NET CLR: {Environment.Version}", Color.Yellow);
    Console.WriteLine($"TensorFlow Binary v{tf.VERSION}");
    Console.WriteLine($"TensorFlow.NET v{Assembly.GetAssembly(typeof(TF_DataType)).GetName().Version}");
    Console.WriteLine($"TensorFlow.Keras v{Assembly.GetAssembly(typeof(KerasApi)).GetName().Version}");
    Console.WriteLine($"{finished} of {examplesLength} example(s) are completed.");
    Console.ReadLine();
}
static (bool, string) RunExamples(Type example, Dictionary<string, string> args)
{
    var instance = (IExample)Activator.CreateInstance(example);
    instance.InitConfig();

    var name = instance.Config.Name;

    // args has "ex" means run specific example
    if (args.ContainsKey("ex") && name != args["ex"])
        return (false, "");

    Console.WriteLine($"{DateTime.UtcNow} Starting {name}", Color.White);

    if (!instance.Config.Enabled)
        return (true, name);

    bool ret = false;
    try
    {
        ret = instance.Run();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    Console.WriteLine($"{DateTime.UtcNow} Completed {name}", Color.White);
    return (ret, name);
}

static Dictionary<string, string> ParseArgs(string[] args)
{
    var parsed = new Dictionary<string, string>();

    for (int i = 0; i < args.Length; i++)
    {
        string key = args[i].Substring(1);
        switch (key)
        {
            case "ex":
                parsed.Add(key, args[++i]);
                break;
            default:
                break;
        }
    }

    return parsed;
}

